2 Codigo Reproducible: Imputación Múltiple - Recalibración de modelo KFRE para predecir falla renal en asegurados de EsSalud

Author

Percy Soto Becerra

1 Code to reproduce results of the manuscript ‘Kidney Failure Prediction: Multicenter External Validation of the KFRE Model in Patients with CKD Stages 3-4 in Peru’

1.1 Introduction

This document presents the code and results of the main analysis shown in the article.

1.2 Setup

rm(list = ls())

# Use pacman to check whether packages are installed, if not load
if (!require("pacman")) install.packages("pacman")
Loading required package: pacman
library(pacman)

# Unload all package to begin in a session with only base packages
pacman::p_unload("all")
The following packages have been unloaded:
pacman
# Install packages
pacman::p_load(
  here, 
  skimr, 
  survival,
  rms,
  cmprsk,
  riskRegression,
  mstate,
  pseudo,
  pec,
  riskRegression,
  plotrix,
  knitr,
  splines,
  kableExtra,
  flextable,
  gtsummary,
  boot,
  tidyverse,
  rsample,
  gridExtra,
  webshot, 
  patchwork,
  survival, 
  cmprsk, 
  survminer, 
  ggsci, 
  cowplot, 
  scales, 
  patchwork, 
  labelled, 
  glue, 
  dcurves, 
  broom, 
  downlit, 
  xml2, 
  gghalves, 
  devtools, 
  htmltools, 
  gghalves, 
  ggtext, 
  DiagrammeR, 
  gt, 
  janitor, 
  VIM, 
  PerformanceAnalytics, 
  mice, 
  rms, 
  naniar, 
  DescTools, 
  gtools, 
  ggExtra, 
  furrr, 
  future, 
  tictoc, 
  parallel,
  ggmice
)

if (!require("impstep")) remotes::install_github("bgravesteijn/impstep", force = TRUE)
Loading required package: impstep
if (!require("smplot2")) devtools::install_github('smin95/smplot2', force = TRUE)
Loading required package: smplot2
Updated tutorial for smplot: smin95.github.io/dataviz/
# You will need Rtools to install packages from Github on Windows
# `devtools` with throw an informative error if Rtools is not found
# if (!"devtools" %in% installed.packages()) install.packages("devtools")
# devtools::install_github("jesse-smith/futuremice")

library(impstep)

## Revisar:; https://amices.org/ggmice/index.html

1.3 Cargar datos

Los datos completos se muestran a continuación, luego de seleccionar a las variables con las que trabajaremos:

# Import data
data <- readRDS(here::here("Data", "Tidy", "datos_total_integrados.rds")) |> 
  select(cas, sex, age, hta, dm, crea, 
         ckd_stage, ckd_stage2, 
         eGFR_ckdepi, acr, urine_album, 
         urine_crea, time5y, eventd5y, 
         grf_cat, acr_cat, ckd_class,
         death2y, eventd2ylab, death5y, 
         eventd5ylab, eventd, time) 

data |> 
  glimpse()
Rows: 152,084
Columns: 23
$ cas         <chr> "Arequipa", "Arequipa", "Arequipa", "Arequipa", "Arequipa"…
$ sex         <fct> Masculino, Masculino, Masculino, Masculino, Masculino, Fem…
$ age         <dbl> 15, 15, 15, 15, 15, 18, 15, 16, NA, NA, NA, 22, 21, NA, 22…
$ hta         <dbl> 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, NA, 0, 1, 0, 1, …
$ dm          <dbl> 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, NA, 0, 0, NA, 0, 0, 0, 1,…
$ crea        <dbl> 0.99, 1.20, 0.97, 0.91, 0.81, 0.76, 0.88, 1.20, 0.75, 0.92…
$ ckd_stage   <fct> Stages 1-2 y 5, Stages 1-2 y 5, Stages 1-2 y 5, Stages 1-2…
$ ckd_stage2  <fct> Stages 1-3 y 5, Stages 1-3 y 5, Stages 1-3 y 5, Stages 1-3…
$ eGFR_ckdepi <dbl> 113.08736, 89.62041, 115.91243, 125.21489, 132.51473, 114.…
$ acr         <dbl> NA, NA, NA, NA, NA, NA, 0.2522603, NA, NA, NA, NA, NA, 392…
$ urine_album <dbl> NA, NA, NA, NA, NA, NA, 22.60, NA, NA, NA, NA, NA, 196.94,…
$ urine_crea  <dbl> NA, NA, NA, NA, NA, NA, 89.5900, NA, 278.1400, 392.2000, 1…
$ time5y      <dbl> 5.0000000, 5.0000000, 5.0000000, 5.0000000, 5.0000000, 4.0…
$ eventd5y    <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
$ grf_cat     <fct> G1, G2, G1, G1, G1, G1, G1, G2, NA, NA, NA, G3b, G1, NA, G…
$ acr_cat     <fct> NA, NA, NA, NA, NA, NA, A1, NA, NA, NA, NA, NA, A3, NA, A3…
$ ckd_class   <fct> NA, NA, NA, NA, NA, NA, Low risk, NA, NA, NA, NA, NA, High…
$ death2y     <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
$ eventd2ylab <chr> "Alive w/o Kidney Failure", "Alive w/o Kidney Failure", "A…
$ death5y     <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
$ eventd5ylab <chr> "Alive w/o Kidney Failure", "Alive w/o Kidney Failure", "A…
$ eventd      <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
$ time        <dbl> 7.4934976, 7.6933607, 7.4934976, 7.9041752, 7.9041752, 4.0…

1.4 Análisis inicial de datos

Vamos a identificar datos de tiempo no plausibles. Se aprecia que todos los datos de tiempo que no son plausibles pertenecen a individuos que hicieron falla renal, y esta implausibilidad se debe a tiempos hasta eventos negativos. Respecto a los datos perdidos, vemos que hay datos perdidos de tiempo tanto en individuos vivos que no reportaron falla renal como en individuos que reportaron falla renal. Como era de esperarse, no hubo datos perdidos de tiempo en individuos que fallecieron, dado que estos datos provienen de la oficina de asegurados que cruza datos con RENIEC. Asimismo, un grupo importante de individuos tuvo datos perdidos de tiempo y de evento (no se sabe si desarrollaron o no falla renal o muerte).

data |> 
  mutate(eventdf = as.character(eventd),
         eventdf = case_match(eventdf, 
                              "0" ~ "Vivo y sin falla renal", 
                              "1" ~ "Falla renal", 
                              "2" ~ "Muerto sin falla renal", 
                              NA ~ "Dato perdido")) |> 
  bind_rows(data |> mutate(eventdf = as.character("Total"))) |> 
  mutate(eventdf = factor(eventdf, 
                          levels = c("Vivo y sin falla renal", 
                                     "Falla renal", 
                                     "Muerto sin falla renal", 
                                     "Total",
                                     "Dato perdido"))) |> 
  count(time, eventdf) |> 
  mutate(time = case_when(is.na(time) ~ 15, 
                          TRUE ~ time), 
         time_tipo = case_when(time > 0 & time < 15 ~ "Valor Plausible", 
                               time <= 0 ~ "Valor Implausible", 
                               time == 15 ~ "Dato perdido", 
                               TRUE ~ as.character(NA))) |> 
  ggplot(aes(x = time, y = n, color = time_tipo)) +
  geom_point(shape = 21, alpha = 0.5) + 
  geom_vline(xintercept = 0.1, linetype = 2, color = "red") +
  scale_y_continuous(trans = "log10") + 
  labs(color = "Tipo de dato") + 
  facet_wrap(. ~ eventdf) + 
  theme_bw() -> p_tiempo_perdido

ggsave(filename = "p_tiempo_perdido.png", 
       plot = p_tiempo_perdido, 
       device = "png", 
       path = here("Figures", "Imputation_Diagnostic"), 
       scale = 2.5, 
       width = 9,
       height = 9, 
       units = "cm", 
       dpi = 600, 
       bg = "white") 

Respecto a la distribución de estos datos perdidos, tenemos lo siguiente:

data |> 
  mutate(eventdf = as.character(eventd),
         eventdf = case_match(eventdf, 
                              "0" ~ "Vivo y sin falla renal", 
                              "1" ~ "Falla renal", 
                              "2" ~ "Muerto sin falla renal", 
                              NA ~ "Dato perdido"), 
         eventdf = factor(eventdf, 
                          levels = c("Vivo y sin falla renal", 
                                     "Falla renal", 
                                     "Muerto sin falla renal", 
                                     "Total",
                                     "Dato perdido")), 
         time_tipo = case_when(time > 0 & time < 15 ~ "Valor Plausible", 
                               time <= 0 ~ "Valor Implausible", 
                               is.na(time) ~ "Dato perdido", 
                               TRUE ~ as.character(NA))) |> 
  tabyl(time_tipo) |> 
  adorn_pct_formatting() -> tabla_tiempo_perdidos

tabla_tiempo_perdidos |> 
  kbl()
time_tipo n percent
Dato perdido 18584 12.2%
Valor Implausible 534 0.4%
Valor Plausible 132966 87.4%

Se aprecia que el porcentaje de datos perdidos de tiempo es de 12.2% (n = 1.8584^{4}). Asimismo, los valores de tiempo implausible son ínfimos y representan el 0.4% (n = 534).

1.5 Seleccion de individuos para el análisis

El total de individuos elegibles es el siguiente:

data_eleg <- data |> 
  filter(age >= 18, ckd_stage == "Stages 3-4")

nrow(data_eleg )
[1] 30488

El número de individuos menores de 18 años es el siguiente:

data_noeleg_age_menos18 <- data |> 
  filter(age < 18)

nrow(data_noeleg_age_menos18)
[1] 145

El número de individuos con datos perdidos en edad es el siguiente:

data_noeleg_age_na <- data |> 
  filter(is.na(age))

nrow(data_noeleg_age_na)
[1] 18610

El número de individuos con diagnostico de CKD diferete a estadio 3a-3:

data_noeleg_ckd12 <- data |> 
  filter(ckd_stage == "Stages 1-2 y 5", eGFR_ckdepi >= 60)

nrow(data_noeleg_ckd12)
[1] 98185
data_noeleg_ckd5 <- data |> 
  filter(ckd_stage == "Stages 1-2 y 5", eGFR_ckdepi < 15)

nrow(data_noeleg_ckd5)
[1] 773

El número de individuos con datos perdidos en el diagnostico de CKD :

data_noeleg_ckd_na <- data |> 
  filter(is.na(ckd_stage))

nrow(data_noeleg_ckd_na)
[1] 22627

El numero de individuos con datos no elegibles de edad o ckd stages es:

data_noeleg_ckd_age <- data |> 
  filter(ckd_stage == "Stages 1-2 y 5" | age < 18)

nrow(data_noeleg_ckd_age)
[1] 98969

El numero de individuos con datos perdidos de edad o perdidos en CKD stages:

data_noeleg_ckd_age_na <- data |> 
  filter(is.na(ckd_stage) | is.na(age))

nrow(data_noeleg_ckd_age_na)
[1] 22627

El numero de individuos potencialmente elgibles por tener edad o CKD stages en el rango o tener datos perdidos

data_eleg_potent <- data |> 
  filter((age >= 18 | is.na(age)) & (ckd_stage == "Stages 3-4" | is.na(ckd_stage)))

nrow(data_eleg_potent)
[1] 53115

El numero individuos incluidos 3a-4:

data_includ <- data_eleg |> 
  filter(time > 0, !is.na(eventd))

nrow(data_includ)
[1] 30031

El numero individuos incluidos 3b-4:

data_includ2 <- data_includ |> 
  filter(ckd_stage2 == "Stages 3b-4")

nrow(data_includ2)
[1] 11540

Los datos excluidos por datos implausibles o perdidos por tiempo son los siguientes

datos_exclud_time_implau <- data_eleg |> 
  filter(time <= 0)

nrow(datos_exclud_time_implau)
[1] 366

Los datos excluidos por datos perdidos en tiempo son los siguientes:

datos_exclud_time_na <- data_eleg |> 
  filter(is.na(time))

nrow(datos_exclud_time_na)
[1] 91

Los datos excluidos por datos perdidos en el status del desenlace:

datos_exclud_eventd_na <- data_eleg |> 
  filter(is.na(eventd))

nrow(datos_exclud_eventd_na)
[1] 91

Los datos excluidos por datos perdidos en el status del desenlace/tiempo o tiempo implausible:

datos_exclud_time_eventd <- data_eleg |> 
  filter(is.na(eventd) | is.na(time) | time <= 0)

nrow(datos_exclud_time_eventd)
[1] 457

1.6 Flujograma de selección / inclusión de participantes

# Create grid of 100 x 100----
data_flow <- tibble(x = 1:100, y = 1:100)

data_flow  %>% 
  ggplot(aes(x, y)) + 
  scale_x_continuous(minor_breaks = seq(1, 100, 1)) + 
  scale_y_continuous(minor_breaks = seq(1, 100, 1)) + 
  theme_linedraw() -> p

# Create boxes----
# 

box_xmin <- 33 - 20
box_xmax <- 75 - 20
box_ymin <- 94
box_ymax <- 99
box_size <- 0.25

text_param <- function(box_min, box_max) {
  mean(c(box_min, box_max))
}

text_size <- 2


p + 
  # Col 0----
  ## Level 1----
  geom_rect(xmin = box_xmin, xmax = box_xmax, 
            ymin = box_ymin - 1, ymax = box_ymax + 1, 
            color = "black", fill = "white", 
            size = box_size) + 
  annotate('text', 
           x = text_param(box_xmin, box_xmax), 
           y = text_param(box_ymin - 1, box_ymax + 1), 
           label = str_glue('Total patients in VISARE database\n(n = {nrow(data)})'), 
           size = text_size ) + 
  ## Level 1.5----
  geom_rect(xmin = box_xmin, xmax = box_xmax, 
            ymin = box_ymin - 27 - 2, ymax = box_ymax - 27 + 2, 
            color = "black", fill = "white", 
            size = box_size) + 
  annotate('text', 
           x = text_param(box_xmin, box_xmax), 
           y = text_param(box_ymin - 27, box_ymax - 27), 
           label = str_glue('Total patients potentially elegible\nwith CKD G3a-G4 and ≥ 18 years old\n(n = {nrow(data_eleg_potent)})'), 
           size = text_size ) + 
  ## Level 2----
  geom_rect(xmin = box_xmin, xmax = box_xmax, 
            ymin = box_ymin - 50 - 1, ymax = box_ymax - 50 + 1, 
            color = "black", fill = "white", 
            size = box_size) + 
  annotate('text', 
           x = text_param(box_xmin, box_xmax), 
           y = text_param(box_ymin - 50 - 1, box_ymax - 50 + 1), 
           label = str_glue('Total patients included in the study\n(n = {nrow(data_eleg)})'), 
           size = text_size ) +   
  # Col -1----
  geom_rect(xmin = box_xmin - 13, xmax = box_xmax - 27, 
            ymin = box_ymin - 81, ymax = box_ymax - 79, 
            color = "black", fill = "white", 
            size = box_size) + 
  annotate('text', 
           x = text_param(box_xmin - 13, box_xmax - 27), 
           y = text_param(box_ymin - 81, box_ymax - 79), 
           label = str_glue('Patients with CKD G3a-G4\n(n = {nrow(data_includ)})'), 
           size = text_size ) + 
  # Col +1----
  ## Level 1----
  geom_rect(xmin = box_xmin + 23, xmax = box_xmax + 47, 
            ymin = box_ymin - 19 + 2.5, ymax = box_ymax - 12 + 2.5, 
            color = "black", fill = "white", 
            size = box_size) + 
  annotate('text', 
           x = text_param(box_xmin + 23, box_xmax + 47), 
           y = text_param(box_ymin - 19 + 2.5, box_ymax - 12 + 2.5), 
           label = str_glue(paste0('Not elegible by age < 18 or CKD in other stages (n = {nrow(data_noeleg_ckd_age)})\n',
                                   '{nrow(data_noeleg_age_menos18)} were less than 18 years old\n', 
                                   '{nrow(data_noeleg_ckd12)} had normal or mildly reduction of eGFR (CKD Stage G1 or G2) \n', 
                                   '{nrow(data_noeleg_ckd5)} had kidney failure (CKD stages G5)\n')), 
           size = text_size )  + 
  ## Level 1.5----
  geom_rect(xmin = box_xmin + 23, xmax = box_xmax + 47, 
            ymin = box_ymin - 19 - 25 + 1.5, ymax = box_ymax - 12 - 25 + 1.5, 
            color = "black", fill = "white", 
            size = box_size) + 
  annotate('text', 
           x = text_param(box_xmin + 23, box_xmax + 47), 
           y = text_param(box_ymin - 19 - 25 + 1.5, box_ymax - 12 - 25 + 1.5), 
           label = str_glue(paste0('Excluded by missing data in selection criteria (n = {nrow(data_noeleg_ckd_age_na)} [{round(100 * nrow(data_noeleg_ckd_age_na)/nrow(data_eleg), 1)}%])\n',
                                   '{nrow(data_noeleg_age_na)} ({round(100 * nrow(data_noeleg_age_na)/nrow(data_eleg), 1)}%) lack of data in age\n', 
                                   '{nrow(data_noeleg_ckd_na)} ({round(100 * nrow(data_noeleg_ckd_na)/nrow(data_eleg), 1)}%) lack of data in eGFR to define CKD stages\n')), 
           size = text_size )  + 
  ## Level 2----
  geom_rect(xmin = box_xmin + 23, xmax = box_xmax + 47, 
            ymin = box_ymin - 19 - 45 - 2, ymax = box_ymax - 12 - 45 - 2, 
            color = "black", fill = "white", 
            size = box_size) + 
  annotate('text', 
           x = text_param(box_xmin + 23, box_xmax + 47), 
           y = text_param(box_ymin - 19 - 45 - 2, box_ymax - 12 - 45 - 2), 
           label = str_glue(paste0('Excluded by missing/implausible data in outcome (n = {nrow(datos_exclud_time_eventd)} [{round(100 * nrow(datos_exclud_time_eventd)/nrow(data_eleg), 1)}%])\n', 
                                   '{nrow(datos_exclud_eventd_na)} ({round(100 * nrow(datos_exclud_eventd_na)/nrow(data_eleg), 1)}%) lack of data in outcome status and time\n', 
                                   '{nrow(datos_exclud_time_implau)} ({round(100 * nrow(datos_exclud_time_implau)/nrow(data_eleg), 1)}%) had negative or zero time-to-event values')), 
           size = text_size )  + 
  ## Level 3----
  geom_rect(xmin = box_xmin + 27, xmax = box_xmax + 13, 
            ymin = box_ymin - 81 , ymax = box_ymax - 79, 
            color = "black", fill = "white", 
            size = box_size) + 
  annotate('text', 
           x = text_param(box_xmin + 27, box_xmax + 13), 
           y = text_param(box_ymin - 81, box_ymax - 79), 
           label = str_glue('Patients with CKD G3b-G4\n(n = {nrow(data_includ2)})'), 
           size = text_size )  + 
  # vertical arrow
  geom_segment(x = text_param(box_xmin, box_xmax), xend = text_param(box_xmin, box_xmax), 
               y = 93, yend = 74, 
               size = 0.15, 
               linejoin = "mitre", 
               lineend = "butt",
               arrow = arrow(length = unit(1, "mm"), type = "closed")) +  
    # vertical arrow
  geom_segment(x = text_param(box_xmin, box_xmax), xend = text_param(box_xmin, box_xmax), 
               y = 65, yend = 50, 
               size = 0.15, 
               linejoin = "mitre", 
               lineend = "butt",
               arrow = arrow(length = unit(1, "mm"), type = "closed")) +  
  geom_segment(x = text_param(box_xmin, box_xmax), xend = text_param(box_xmin, box_xmax), 
               y =43, yend = 25, 
               size = 0.15, 
               linejoin = "mitre", 
               lineend = "butt") + 
  # horizontal arrow 1-->
  geom_segment(x = text_param(box_xmin, box_xmax), xend = box_xmin + 23, 
               y = text_param(box_ymin - 19 + 2, box_ymax - 12 + 2), yend = text_param(box_ymin - 19 + 2, box_ymax - 12 + 2), 
               size = 0.15, 
               linejoin = "mitre", 
               lineend = "butt", 
               arrow = arrow(length = unit(1, "mm"), type = "closed")) + 
  # horizontal arrow 2-->
  geom_segment(x = text_param(box_xmin, box_xmax), xend = box_xmin + 23, 
               y = text_param(box_ymin - 19 - 45, box_ymax - 12 - 45), yend = text_param(box_ymin - 19 - 45, box_ymax - 12 - 45), 
               size = 0.15, 
               linejoin = "mitre", 
               lineend = "butt", 
               arrow = arrow(length = unit(1, "mm"), type = "closed")) + 
  # horizontal arrow 2-->
  geom_segment(x = text_param(box_xmin, box_xmax), xend = box_xmin + 23, 
               y = text_param(box_ymin - 19 - 25 + 1, box_ymax - 12 - 25 + 1), yend = text_param(box_ymin - 19 - 25 + 1, box_ymax - 12 - 25 + 1), 
               size = 0.15, 
               linejoin = "mitre", 
               lineend = "butt", 
               arrow = arrow(length = unit(1, "mm"), type = "closed")) + 
  # horizontal segment --
  geom_segment(x = text_param(box_xmin - 13, box_xmax - 27), xend = text_param(box_xmin + 27, box_xmax + 13), 
               y = 25, yend = 25, 
               size = 0.15, 
               linejoin = "mitre", 
               lineend = "butt") + 
  # vertical arrow -->
  geom_segment(x = text_param(box_xmin - 13, box_xmax - 27), xend = text_param(box_xmin - 13, box_xmax - 27), 
               y = 25, yend = box_ymax - 79, 
               size = 0.15, 
               linejoin = "mitre", 
               lineend = "butt", 
               arrow = arrow(length = unit(1, "mm"), type = "closed")) + 
  # vertical arrow -->
  geom_segment(x = text_param(box_xmin + 27, box_xmax + 13), xend = text_param(box_xmin + 27, box_xmax + 13), 
               y = 25, yend = box_ymax - 79, 
               size = 0.15, 
               linejoin = "mitre", 
               lineend = "butt", 
               arrow = arrow(length = unit(1, "mm"), type = "closed")) + 
  theme_void() +
  theme(plot.background = element_rect(fill = "white")) -> plot_flowchart
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.
ggsave(filename = "plot_flowchart.png", 
       plot = plot_flowchart, 
       device = "png", 
       path = here("Figures"), 
       scale = 1, 
       width = 12, 
       height = 12, 
       units = "cm", 
       dpi = 600)
knitr::include_graphics(here("Figures", "plot_flowchart.png"))

1.7 Distribucion de datos según region

data |> 
  mutate(inclusion = case_when(age >= 18 & time > 0 & ckd_stage == "Stages 3-4" ~ "Incluido", 
                               TRUE ~ "No incluido"), 
         cas = fct_rev(fct_infreq(cas))) |> 
  ggplot(aes(x = cas, fill = factor(inclusion, level = c("Incluido", "No incluido")))) + 
  geom_bar() +  
  labs(fill = "Inclusión", x = NULL, y = "Frecuencia absoluta") + 
  coord_flip(expand = FALSE) + 
  scale_y_continuous(limits = c(0, 30000)) + 
  theme_bw() -> p1 

data |> 
  mutate(inclusion = case_when(age >= 18 & time > 0 & ckd_stage == "Stages 3-4" ~ "Incluido", 
                               TRUE ~ "No incluido"), 
         cas = fct_rev(fct_infreq(cas))) |> 
  ggplot(aes(x = cas, fill = factor(inclusion, level = c("Incluido", "No incluido")))) + 
  geom_bar(position = "fill") +  
  labs(fill = "Inclusión", x = NULL, y = "Proporción") + 
  coord_flip(expand = FALSE) + 
  scale_y_continuous(limits = c(0, 1)) + 
  theme_bw()  + 
  theme(axis.text.y = element_blank(),
        axis.ticks.y = element_blank()) -> p2

data |> 
  mutate(inclusion = case_when(age >= 18 & time > 0 & ckd_stage == "Stages 3-4" ~ "Incluido", 
                               TRUE ~ "No incluido"), 
         cas = fct_rev(fct_infreq(cas))) |> 
  filter(inclusion == "Incluido") |> 
  ggplot(aes(x = cas)) + 
  geom_bar(fill = "#F8766D") +  
  labs(x = NULL, y = "Frecuencia absoluta") + 
  coord_flip(expand = FALSE) + 
  scale_y_continuous(limits = c(0, 11000)) + 
  theme_bw() + 
  theme(axis.text.y = element_blank(),
        axis.ticks.y = element_blank()) -> p3

(p1 | p3 | p2) + 
  plot_layout(guides = "collect") -> plot_region

ggsave(filename = "plot_region.png", 
       plot = plot_region, 
       device = "png", 
       path = here("Figures"), 
       scale = 2, 
       width = 12,
       height = 9, 
       units = "cm", 
       dpi = 600, 
       bg = "white") 

1.8 Selección de pacientes incluidos en estudio

# Subset patients with CKD Stages 3a-3b-4
data %>%  
  # Criterio de seleccion
  filter(age >= 18, time > 0) |> 
  filter(ckd_stage == "Stages 3-4") |> 
  # Preparacion de datos
  select(cas, sex, age, hta, dm, crea, ckd_stage2, 
         eGFR_ckdepi, acr, urine_album, 
         urine_crea, time5y, eventd5y, 
         grf_cat, acr_cat, ckd_class,
         death2y, eventd2ylab, death5y, 
         eventd5ylab, eventd, time) |> 
  mutate(hta = factor(hta), 
         dm = factor(dm),
         cas2 = case_when(cas %in% c("Lima - Rebagliati") ~ "Lima - Rebagliati", 
                          cas %in% c("Lima - Almenara", "Lima - Sabogal") ~ "Lima Otros", 
                          TRUE ~ "Otras Redes"), 
         cas = fct_rev(fct_infreq(cas)), 
         cas2 = fct_rev(fct_infreq(cas2))
         ) |> 
  mutate(acr = Winsorize(acr, probs = c(0.01, 0.99), na.rm = TRUE), 
         urine_album = Winsorize(urine_album, probs = c(0.01, 0.99), na.rm = TRUE), 
         urine_crea = Winsorize(urine_crea, probs = c(0.01, 0.99), na.rm = TRUE), 
         eventd2ylab = factor(eventd2ylab, 
                              levels = c("Alive w/o Kidney Failure", 
                                         "Kidney Failure", 
                                         "Death w/o Kidney Failure")), 
         eventd5ylab = factor(eventd5ylab, 
                              levels = c("Alive w/o Kidney Failure", 
                                         "Kidney Failure", 
                                         "Death w/o Kidney Failure"))) -> dataA

# Subset patients with CKD Stages 3b-4
data %>% 
  # Criterio de seleccion
  filter(age >= 18, time > 0) |> 
  filter(ckd_stage2 == "Stages 3b-4") |> 
  # Preparacion de datos
  select(cas, sex, age, hta, dm, crea, 
         eGFR_ckdepi, acr, urine_album, 
         urine_crea, time5y, eventd5y, 
         grf_cat, acr_cat, ckd_class,  
         death2y, eventd2ylab, death5y, 
         eventd5ylab, eventd, time) |> 
  mutate(hta = factor(hta), 
         dm = factor(dm),
         cas2 = case_when(cas %in% c("Lima - Rebagliati") ~ "Lima - Rebagliati", 
                          cas %in% c("Lima - Almenara", "Lima - Sabogal") ~ "Lima Otros", 
                          TRUE ~ "Otras Redes"), 
         cas = fct_rev(fct_infreq(cas)), 
         cas2 = fct_rev(fct_infreq(cas2))
         ) |> 
  mutate(acr = Winsorize(acr, probs = c(0.01, 0.99), na.rm = TRUE), 
         urine_album = Winsorize(urine_album, probs = c(0.01, 0.99), na.rm = TRUE), 
         urine_crea = Winsorize(urine_crea, probs = c(0.01, 0.99), na.rm = TRUE), 
         eventd2ylab = factor(eventd2ylab, 
                              levels = c("Alive w/o Kidney Failure", 
                                         "Kidney Failure", 
                                         "Death w/o Kidney Failure")), 
         eventd5ylab = factor(eventd5ylab, 
                              levels = c("Alive w/o Kidney Failure", 
                                         "Kidney Failure", 
                                         "Death w/o Kidney Failure"))) -> dataB

1.9 Cargar Funciones Escritas por Usuario

source(here("Code", "source", "kfre_pi.R"))
source(here("Code", "source", "kfre_pr.R"))
source(here("Code", "source", "oe_ratio.R"))
source(here("Code", "source", "calibration_intercept.R"))
source(here("Code", "source", "calibration_slope.R"))
source(here("Code", "source", "auc.R"))
source(here("Code", "source", "validate.mids.R"))
source(here("Code", "source", "pool.validate.mids.R"))
source(here("Code", "source", "pool.auc.mids.R"))
source(here("Code", "source", "predict.mira.R"))
source(here("Code", "source", "process_imp_cal_plot.R"))

1.10 Creacion de hazard acumulado causa especifico mediante estimador de Nelson-Aalen

cumhaz1 <- basehaz(coxph(Surv(time, eventd == 1) ~ 1, data = dataA)) |> 
  rename(cumhaz1 = hazard)
cumhaz2 <- basehaz(coxph(Surv(time, eventd == 2) ~ 1, data = dataA))|> 
  rename(cumhaz2 = hazard)

dataA <- dataA |> 
  left_join(cumhaz1, by = "time") |> 
  left_join(cumhaz2, by = "time")

1.11 Preparación de datos

dataA_imp <- dataA |> 
  mutate(eventdf = factor(eventd, levels = c(0, 1, 2))) |> 
  select(-ckd_class, -acr_cat) |> 
  mutate(sex_cumhaz1 = as.integer(sex == "Masculino") * (cumhaz1 - mean(cumhaz1)), 
         age_cumhaz1 = (age - mean(age)) * (cumhaz1 - mean(cumhaz1)), 
         eGFR_ckdepi_cumhaz1 = (eGFR_ckdepi - mean(age)) * (cumhaz1 - mean(cumhaz1)), 
         sex_cumhaz2 = as.integer(sex == "Masculino") * (cumhaz2 - mean(cumhaz2)), 
         age_cumhaz2 = (age - mean(age)) * (cumhaz2 - mean(cumhaz2)), 
         eGFR_ckdepi_cumhaz2 = (eGFR_ckdepi - mean(age)) * (cumhaz2 - mean(cumhaz2)), 
         log_urine_crea = log(urine_crea), 
         log_urine_album = log(urine_album),
         log_acr = log(acr)) |> 
  select(-urine_crea, -urine_album, -acr) |> 
  relocate(all_of(c("hta", "dm", "log_urine_crea", "log_acr", "log_urine_album")), 
           .after = eGFR_ckdepi_cumhaz2)

1.12 Exploración de datos perdidos

Las variables a tener en cuenta se muestran a continuacion:

dataA |> 
  glimpse()
Rows: 30,031
Columns: 25
$ cas         <fct> Lima - Rebagliati: JB, Lima - Rebagliati: JB, KAELIN, KAEL…
$ sex         <fct> Femenino, Femenino, Masculino, Femenino, Femenino, Femenin…
$ age         <dbl> 22, 22, 93, 50, 66, 79, 65, 20, 61, 78, 59, 82, 18, 78, 80…
$ hta         <fct> 1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ dm          <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ crea        <dbl> 2.10, 3.11, 1.58, 2.84, 1.69, 1.37, 1.34, 2.74, 1.12, 1.36…
$ ckd_stage2  <fct> Stages 3b-4, Stages 3b-4, Stages 3b-4, Stages 3b-4, Stages…
$ eGFR_ckdepi <dbl> 32.68936, 20.33397, 37.15369, 18.64175, 31.20480, 36.70976…
$ acr         <dbl> NA, 1598.9600, 185.8228, 31514.9800, 10527.1500, 27.9000, …
$ urine_album <dbl> NA, 52.03, 7.34, 1451.58, 416.77, NA, 561.40, 12.36, 0.30,…
$ urine_crea  <dbl> NA, 32.50, 39.50, 46.06, 39.59, NA, 51.30, 42.00, 35.68, 6…
$ time5y      <dbl> 2.9842574, 2.8035592, 0.5010267, 5.0000000, 5.0000000, 0.8…
$ eventd5y    <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0…
$ grf_cat     <fct> G3b, G4, G3b, G4, G3b, G3b, G3b, G4, G3a, G3a, G4, G3b, G3…
$ acr_cat     <fct> NA, A3, A2, A3, A3, A1, A3, A2, A1, A3, A3, A3, A2, A2, A2…
$ ckd_class   <fct> NA, Very high risk, Very high risk, Very high risk, Very h…
$ death2y     <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
$ eventd2ylab <fct> Alive w/o Kidney Failure, Alive w/o Kidney Failure, Alive …
$ death5y     <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0…
$ eventd5ylab <fct> Alive w/o Kidney Failure, Alive w/o Kidney Failure, Alive …
$ eventd      <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 2, 0, 0…
$ time        <dbl> 2.9842574, 2.8035592, 0.5010267, 5.4154689, 6.5817933, 0.8…
$ cas2        <fct> Otras Redes, Otras Redes, Otras Redes, Otras Redes, Otras …
$ cumhaz1     <dbl> 0.039036846, 0.037272186, 0.008296835, 0.056070997, 0.0601…
$ cumhaz2     <dbl> 0.12066670, 0.11277426, 0.01513545, 0.25513897, 0.33189356…

La cantidad de datos perdidos por variable es la siguiente:

dataA |> 
  select(-c(ckd_stage2, time5y, eventd5y, acr_cat, 
            death2y, eventd2ylab, death5y, eventd5ylab, time, cas)) |> 
  miss_var_summary() |> 
  kbl()
variable n_miss pct_miss
urine_album 21249 70.75688
acr 20213 67.30712
ckd_class 20213 67.30712
urine_crea 16739 55.73907
dm 8606 28.65705
hta 5715 19.03034
sex 0 0.00000
age 0 0.00000
crea 0 0.00000
eGFR_ckdepi 0 0.00000
grf_cat 0 0.00000
eventd 0 0.00000
cas2 0 0.00000
cumhaz1 0 0.00000
cumhaz2 0 0.00000

A continuación se muestra un gráfico de patrón de datos perdidos. Podemos apreciar un patrón de datos general, caracterizado por tener datos perdidos multivariado, no se aprecia ningún patrón monótono de datos perdidos (como era de esperarse) y tampoco existe file matching. ASimismo, se aprecia que los datos perdidos muestran un patrón conectado a nivel de filas y columnas.

dataA |> 
  select(-c(ckd_stage2, time5y, eventd5y, acr_cat, ckd_class,
            death2y, eventd2ylab, death5y, eventd5ylab, time, cas)) |> 
  plot_pattern(rotate = TRUE) -> plot_patterns

ggsave(filename = "plot_patterns.png", 
       plot = plot_patterns, 
       device = "png", 
       path = here("Figures", "Imputation_Diagnostic"), 
       scale = 2, 
       width = 9,
       height = 9, 
       units = "cm", 
       dpi = 600, 
       bg = "white") 

1.13 Influx - outflux

dataA |> 
  select(-c(ckd_stage2, time5y, eventd5y, acr_cat, ckd_class,
            death2y, eventd2ylab, death5y, eventd5ylab, cas)) |> 
  plot_flux(label = FALSE) -> plot_influx

# Primero, averiguamos cuántas capas hay.
num_layers <- length(plot_influx$layers)

# Examinamos cada capa para encontrar la geom_point() que no deseamos.
# Esto imprimirá las capas y deberías buscar la que contiene la geom_point sin shape.
for (i in 1:num_layers) {
  print(plot_influx$layers[[i]])
}
mapping: intercept = ~intercept, slope = ~slope 
geom_abline: na.rm = FALSE
stat_identity: na.rm = FALSE
position_identity 
geom_point: na.rm = FALSE
stat_identity: na.rm = FALSE
position_nudge 
# Eliminamos la capa geom_point que no queremos.
# La salida muestra que es la segunda capa, así que la eliminamos.
plot_influx$layers <- plot_influx$layers[-2] 

# Asegúrate de tener suficientes formas para cada nivel único de la variable.
unique_vrbs <- unique(plot_influx$data$vrb)
shapes <- seq_along(unique_vrbs)

# Ahora deberías volver a agregar la capa geom_point con las formas y colores adecuados.
plot_influx <- plot_influx + 
  geom_jitter(aes(shape = vrb, colour = vrb), width = 0.025, height = 0.025) +
  scale_shape_manual(values = shapes) +
  guides(colour = guide_legend(override.aes = list(shape = shapes)),
         shape = FALSE)
Warning: The `<scale>` argument of `guides()` cannot be `FALSE`. Use "none" instead as
of ggplot2 3.3.4.
ggsave(filename = "plot_influx.png", 
       plot = plot_influx, 
       device = "png", 
       path = here("Figures", "Imputation_Diagnostic"), 
       scale = 2, 
       width = 9,
       height = 9, 
       units = "cm", 
       dpi = 600, 
       bg = "white") 

1.14 Por region

dataA |> 
  mutate(miss_acr = if_else(is.na(acr), "Missing", "Completo"), 
         miss_acr = factor(miss_acr, level = c("Completo", "Missing"))) |> 
  ggplot(aes(x = cas, fill = miss_acr)) + 
  geom_bar(position = "fill") +  
  labs(fill = "Datos perdidos", x = NULL, y = "Proporción") + 
  coord_flip(expand = FALSE) + 
  scale_y_continuous(limits = c(0, 1)) + 
  theme_bw() -> p1

dataA |> 
  mutate(miss_acr = if_else(is.na(acr), "Missing", "Completo"), 
         miss_acr = factor(miss_acr, level = c("Completo", "Missing"))) |> 
  ggplot(aes(x = cas, fill = miss_acr)) + 
  geom_bar() +  
  labs(fill = "Datos perdidos", x = NULL, y = "Frecuencia absoluta") + 
  coord_flip(expand = FALSE) + 
  scale_y_continuous(limits = c(0, 10000)) + 
  theme_bw()  -> p2

(p1 | p2) + plot_layout(guides = "collect") -> plot_region_missing

ggsave(filename = "plot_region_missing.png", 
       plot = plot_region_missing, 
       device = "png", 
       path = here("Figures", "Imputation_Diagnostic"), 
       scale = 2, 
       width = 16,
       height = 8, 
       units = "cm", 
       dpi = 600, 
       bg = "white") 

dataA |> 
  mutate(miss_acr = if_else(is.na(acr), "Missing", "Completo"), 
         miss_acr = factor(miss_acr, level = c("Completo", "Missing"))) |> 
  ggplot(aes(x = cas2, fill = miss_acr)) + 
  geom_bar(position = "fill") +  
  labs(fill = "Datos perdidos", x = NULL, y = "Proporción") + 
  coord_flip(expand = FALSE) + 
  scale_y_continuous(limits = c(0, 1)) + 
  theme_bw() -> p1

dataA |> 
  mutate(miss_acr = if_else(is.na(acr), "Missing", "Completo"), 
         miss_acr = factor(miss_acr, level = c("Completo", "Missing"))) |> 
  ggplot(aes(x = cas2, fill = miss_acr)) + 
  geom_bar() +  
  labs(fill = "Datos perdidos", x = NULL, y = "Frecuencia absoluta") + 
  coord_flip(expand = FALSE) + 
  scale_y_continuous(limits = c(0, 16000)) + 
  theme_bw()  -> p2

(p1 | p2) + plot_layout(guides = "collect") -> plot_region_missing

ggsave(filename = "plot_region_missing2.png", 
       plot = plot_region_missing, 
       device = "png", 
       path = here("Figures", "Imputation_Diagnostic"), 
       scale = 2, 
       width = 16,
       height = 6, 
       units = "cm", 
       dpi = 600, 
       bg = "white") 
Warning: Removed 2 rows containing missing values (`geom_bar()`).

1.15 Inicializar MICE

Se inicia con maxit = 0 para verificar que no haya errores

setup_impA <- mice(dataA_imp, maxit = 0)
Warning: Number of logged events: 2

Se verifica si hay eventos que revisar

setup_impA$loggedEvents

Se revisa que modelos de imputacion

make.method(dataA_imp)
                cas                 sex                 age                crea 
                 ""                  ""                  ""                  "" 
         ckd_stage2         eGFR_ckdepi              time5y            eventd5y 
                 ""                  ""                  ""                  "" 
            grf_cat             death2y         eventd2ylab             death5y 
                 ""                  ""                  ""                  "" 
        eventd5ylab              eventd                time                cas2 
                 ""                  ""                  ""                  "" 
            cumhaz1             cumhaz2             eventdf         sex_cumhaz1 
                 ""                  ""                  ""                  "" 
        age_cumhaz1 eGFR_ckdepi_cumhaz1         sex_cumhaz2         age_cumhaz2 
                 ""                  ""                  ""                  "" 
eGFR_ckdepi_cumhaz2                 hta                  dm      log_urine_crea 
                 ""            "logreg"            "logreg"               "pmm" 
            log_acr     log_urine_album 
              "pmm"               "pmm" 
predA <- make.predictorMatrix(dataA_imp)
plot_pred(predA, rotate = TRUE) 

predA[, "crea"] <- 0
predA[, "time5y"] <- 0
predA[, "eventd5y"] <- 0
predA[, "death2y"] <- 0
predA[, "eventd2ylab"] <- 0
predA[, "death5y"] <- 0
predA[, "eventd5ylab"] <- 0
predA[, "eventd"] <- 0
predA[, "time"] <- 0
predA[, "ckd_stage2"] <- 0
predA[, "grf_cat"] <- 0
predA[, "cas"] <- 0


predA["crea", ] <- 0
predA["time5y", ] <- 0
predA["eventd5y", ] <- 0
predA["death2y", ] <- 0
predA["eventd2ylab", ] <- 0
predA["death5y", ] <- 0
predA["eventd5ylab", ] <- 0
predA["eventd", ] <- 0
predA["time", ] <- 0
predA["ckd_stage2", ] <- 0
predA["grf_cat", ] <- 0
predA["cas", ] <- 0

predA[c("log_urine_crea", "log_acr"), c("log_urine_crea", "log_acr")] <- 0
predA[c("log_urine_album", "log_acr"), c("log_urine_album", "log_acr")] <- 0
methA <- make.method(dataA_imp)
methA
                cas                 sex                 age                crea 
                 ""                  ""                  ""                  "" 
         ckd_stage2         eGFR_ckdepi              time5y            eventd5y 
                 ""                  ""                  ""                  "" 
            grf_cat             death2y         eventd2ylab             death5y 
                 ""                  ""                  ""                  "" 
        eventd5ylab              eventd                time                cas2 
                 ""                  ""                  ""                  "" 
            cumhaz1             cumhaz2             eventdf         sex_cumhaz1 
                 ""                  ""                  ""                  "" 
        age_cumhaz1 eGFR_ckdepi_cumhaz1         sex_cumhaz2         age_cumhaz2 
                 ""                  ""                  ""                  "" 
eGFR_ckdepi_cumhaz2                 hta                  dm      log_urine_crea 
                 ""            "logreg"            "logreg"               "pmm" 
            log_acr     log_urine_album 
              "pmm"               "pmm" 
plot_pred(predA,  
          rotate = TRUE) -> plot_matriz_pred

ggsave(filename = "plot_matriz_pred.png", 
       plot = plot_matriz_pred, 
       device = "png", 
       path = here("Figures", "Imputation_Diagnostic"), 
       scale = 2, 
       width = 9,
       height = 9, 
       units = "cm", 
       dpi = 600, 
       bg = "white") 

1.16 Imputation

n_cores <- detectCores()
n_cores
[1] 8
# Evaluate futures in parallel - max of two workers to avoid hogging resources
future::plan("multisession", workers = n_cores)
tic()
data_impA <- futuremice(dataA_imp, 
                        method = methA, 
                        m = 100, 
                        maxit = 500, 
                        pred = predA, 
                        n.core = n_cores)
toc()
11331.43 sec elapsed
data_impA$loggedEvents
NULL
semilla_reproducible <- data.frame(semilla = data_impA$parallelseed)
data_impA$visitSequence
 [1] "cas"                 "sex"                 "age"                
 [4] "crea"                "ckd_stage2"          "eGFR_ckdepi"        
 [7] "time5y"              "eventd5y"            "grf_cat"            
[10] "death2y"             "eventd2ylab"         "death5y"            
[13] "eventd5ylab"         "eventd"              "time"               
[16] "cas2"                "cumhaz1"             "cumhaz2"            
[19] "eventdf"             "sex_cumhaz1"         "age_cumhaz1"        
[22] "eGFR_ckdepi_cumhaz1" "sex_cumhaz2"         "age_cumhaz2"        
[25] "eGFR_ckdepi_cumhaz2" "hta"                 "dm"                 
[28] "log_urine_crea"      "log_acr"             "log_urine_album"    
plot_trace(data_impA) + 
  theme(legend.position="none") -> plot_trace_dx

ggsave(filename = "plot_trace_dx.png", 
       plot = plot_trace_dx, 
       device = "png", 
       path = here("Figures", "Imputation_Diagnostic"), 
       scale = 2.5, 
       width = 12,
       height = 6, 
       units = "cm", 
       dpi = 600, 
       bg = "white") 

mean_converg <- convergence(data_impA, diagnostic = "all", parameter = "mean") |> 
  mutate(type = "mean")
sd_converg <- convergence(data_impA, diagnostic = "all", parameter = "sd") |> 
  mutate(type = "sd") 

mean_converg |> 
  bind_rows(sd_converg) |> 
  filter(vrb %in% c("hta", "dm", "log_urine_crea", "log_urine_album", 
                    "log_acr")) |> 
  ggplot(aes(x = .it, y = ac, color = type)) + 
  geom_line() + 
  geom_hline(yintercept = 0) + 
  facet_grid(type ~ vrb) + 
  theme_bw() -> plot_autocor_dx

ggsave(filename = "plot_autocor_dx.png", 
       plot = plot_autocor_dx, 
       device = "png", 
       path = here("Figures", "Imputation_Diagnostic"), 
       scale = 2.5, 
       width = 12,
       height = 6, 
       units = "cm", 
       dpi = 600, 
       bg = "white") 
Warning: Removed 2 rows containing missing values (`geom_line()`).

mean_converg |> 
  bind_rows(sd_converg) |> 
  filter(vrb %in% c("hta", "dm", "log_urine_crea", "log_urine_album", 
                    "log_acr")) |> 
  ggplot(aes(x = .it, y = psrf, color = type)) + 
  geom_line() + 
  geom_hline(yintercept = 1) + 
  facet_grid(type ~ vrb) + 
  theme_bw()-> plot_psrf_dx

ggsave(filename = "plot_psrf_dx.png", 
       plot = plot_psrf_dx, 
       device = "png", 
       path = here("Figures", "Imputation_Diagnostic"), 
       scale = 2.5, 
       width = 12,
       height = 6, 
       units = "cm", 
       dpi = 600, 
       bg = "white") 

densityplot(data_impA, ~ log_urine_crea)
Hint: Did you know, an equivalent figure can be created with `ggmice()`?
For example, to plot a variable named 'my_vrb' from a mids object called
'my_mids', run:
  ggmice(my_mids, ggplot2::aes(x = my_vrb, group = .imp)) +
  ggplot2::geom_density()
ℹ See amices.org/ggmice for more info.
This message is displayed once per session.

densityplot(data_impA, ~ log_urine_album)

densityplot(data_impA, ~ log_acr)

1.16.1 Datos apilados

saveRDS(data_impA, here("Data", "Tidy", "data_impA.rds"))
saveRDS(semilla_reproducible, here("Data", "Tidy", "semilla_reproducible.rds"))

1.17 Ticket de Reprocubilidad

sessionInfo()
R version 4.3.3 (2024-02-29 ucrt)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19045)

Matrix products: default


locale:
[1] LC_COLLATE=Spanish_Spain.utf8  LC_CTYPE=Spanish_Spain.utf8   
[3] LC_MONETARY=Spanish_Spain.utf8 LC_NUMERIC=C                  
[5] LC_TIME=Spanish_Spain.utf8    

time zone: America/Lima
tzcode source: internal

attached base packages:
 [1] parallel  grid      splines   stats     graphics  grDevices utils    
 [8] datasets  methods   base     

other attached packages:
 [1] smplot2_0.1.0              impstep_0.1.0             
 [3] ggmice_0.1.0               tictoc_1.2                
 [5] furrr_0.3.1                future_1.33.2             
 [7] ggExtra_0.10.1             gtools_3.9.5              
 [9] DescTools_0.99.54          naniar_1.0.0              
[11] mice_3.16.0                PerformanceAnalytics_2.0.4
[13] xts_0.13.1                 zoo_1.8-12                
[15] VIM_6.2.2                  colorspace_2.1-0          
[17] janitor_2.2.0              gt_0.10.0                 
[19] DiagrammeR_1.0.10          ggtext_0.1.2              
[21] htmltools_0.5.7            devtools_2.4.5            
[23] usethis_2.2.2              gghalves_0.1.4            
[25] xml2_1.3.5                 downlit_0.4.3             
[27] broom_1.0.5                dcurves_0.4.0             
[29] glue_1.6.2                 labelled_2.12.0           
[31] scales_1.3.0               cowplot_1.1.2             
[33] ggsci_3.0.0                survminer_0.4.9           
[35] ggpubr_0.6.0               patchwork_1.1.3           
[37] webshot_0.5.5              gridExtra_2.3             
[39] rsample_1.2.0              lubridate_1.9.3           
[41] forcats_1.0.0              stringr_1.5.1             
[43] dplyr_1.1.4                purrr_1.0.2               
[45] readr_2.1.5                tidyr_1.3.1               
[47] tibble_3.2.1               ggplot2_3.4.4             
[49] tidyverse_2.0.0            boot_1.3-29               
[51] gtsummary_1.7.2            flextable_0.9.4           
[53] kableExtra_1.3.4           knitr_1.45                
[55] plotrix_3.8-4              pec_2023.04.12            
[57] prodlim_2023.08.28         pseudo_1.4.3              
[59] geepack_1.3.9              KMsurv_0.1-5              
[61] mstate_0.3.2               riskRegression_2023.09.08 
[63] cmprsk_2.2-11              rms_6.7-1                 
[65] Hmisc_5.1-1                survival_3.5-8            
[67] skimr_2.1.5                here_1.0.1                

loaded via a namespace (and not attached):
  [1] matrixStats_1.1.0       fs_1.6.3                httr_1.4.7             
  [4] RColorBrewer_1.1-3      repr_1.1.6              numDeriv_2016.8-1.1    
  [7] profvis_0.3.8           tools_4.3.3             backports_1.4.1        
 [10] utf8_1.2.4              R6_2.5.1                jomo_2.7-6             
 [13] urlchecker_1.0.1        withr_3.0.0             sp_2.0-0               
 [16] quantreg_5.97           cli_3.6.1               textshaping_0.3.7      
 [19] pacman_0.5.1            officer_0.6.3           sandwich_3.0-2         
 [22] labeling_0.4.3          mvtnorm_1.2-4           survMisc_0.5.6         
 [25] robustbase_0.99-0       polspline_1.1.24        proxy_0.4-27           
 [28] askpass_1.2.0           QuickJSR_1.0.8          StanHeaders_2.26.28    
 [31] systemfonts_1.0.5       foreign_0.8-86          gfonts_0.2.0           
 [34] svglite_2.1.2           parallelly_1.37.1       sessioninfo_1.2.2      
 [37] pwr_1.3-0               readxl_1.4.3            rstudioapi_0.15.0      
 [40] httpcode_0.3.0          shape_1.4.6.1           visNetwork_2.1.2       
 [43] generics_0.1.3          car_3.1-2               zip_2.3.0              
 [46] inline_0.3.19           loo_2.6.0               Matrix_1.6-1           
 [49] fansi_1.0.6             abind_1.4-5             lifecycle_1.0.4        
 [52] multcomp_1.4-25         yaml_2.3.7              snakecase_0.11.1       
 [55] carData_3.0-5           promises_1.2.1          mitml_0.4-5            
 [58] crayon_1.5.2            miniUI_0.1.1.1          lattice_0.22-5         
 [61] haven_2.5.4             pillar_1.9.0            gld_2.6.6              
 [64] future.apply_1.11.0     codetools_0.2-19        pan_1.9                
 [67] V8_4.4.0                fontLiberation_0.1.0    data.table_1.14.8      
 [70] broom.helpers_1.14.0    remotes_2.4.2.1         vcd_1.4-11             
 [73] png_0.1-8               vctrs_0.6.4             cellranger_1.1.0       
 [76] gtable_0.3.4            cachem_1.0.8            xfun_0.40              
 [79] mime_0.12               iterators_1.0.14        lava_1.7.3             
 [82] ellipsis_0.3.2          TH.data_1.1-2           nlme_3.1-164           
 [85] fontquiver_0.2.1        rstan_2.32.3            rprojroot_2.0.4        
 [88] rpart_4.1.23            nnet_7.3-19             Exact_3.2              
 [91] tidyselect_1.2.1        sdamr_0.2.0             compiler_4.3.3         
 [94] curl_5.1.0              glmnet_4.1-8            rvest_1.0.3            
 [97] htmlTable_2.4.2         expm_0.999-7            SparseM_1.81           
[100] fontBitstreamVera_0.1.1 checkmate_2.3.0         DEoptimR_1.1-3         
[103] lmtest_0.9-40           quadprog_1.5-8          digest_0.6.33          
[106] minqa_1.2.6             rmarkdown_2.25          pkgconfig_2.0.3        
[109] base64enc_0.1-3         lme4_1.1-35.2           highr_0.10             
[112] fastmap_1.1.1           rlang_1.1.2             htmlwidgets_1.6.3      
[115] shiny_1.8.0             farver_2.1.1            jsonlite_1.8.8         
[118] magrittr_2.0.3          Formula_1.2-5           munsell_0.5.0          
[121] Rcpp_1.0.11             gdtools_0.3.4           visdat_0.6.0           
[124] stringi_1.7.12          rootSolve_1.8.2.4       MASS_7.3-60.0.1        
[127] pkgbuild_1.4.4          listenv_0.9.1           lmom_3.0               
[130] mets_1.3.2              gridtext_0.1.5          hms_1.1.3              
[133] timereg_2.0.5           uuid_1.1-1              ranger_0.15.1          
[136] ggsignif_0.6.4          stats4_4.3.3            pkgload_1.3.4          
[139] crul_1.4.0              evaluate_0.23           RcppParallel_5.1.7     
[142] laeken_0.5.2            nloptr_2.0.3            tzdb_0.4.0             
[145] foreach_1.5.2           httpuv_1.6.12           MatrixModels_0.5-3     
[148] openssl_2.1.1           km.ci_0.5-6             xtable_1.8-4           
[151] e1071_1.7-13            rstatix_0.7.2           later_1.3.1            
[154] viridisLite_0.4.2       class_7.3-22            ragg_1.2.6             
[157] memoise_2.0.1           cluster_2.1.5           timechange_0.2.0       
[160] globals_0.16.3